#pragma once
#include "reactor.hpp"
#include "util.hpp"
#include<iostream>
#include <vector>


namespace ns_appinterface {

	int recver(ns_epoll::EventItem* item);
	int sender(ns_epoll::EventItem * item);
	int errorer(ns_epoll::EventItem * item);

	int accepter(ns_epoll::EventItem* item) {
		std::cout << "get a new link [fd:" << item->sock <<"]" << std::endl;
		while (true) {
			struct sockaddr_in peer;
			socklen_t len = sizeof(peer);
			int sock = accept(item->sock, (struct sockaddr*)&peer, &len);

			if (sock < 0) {
				if (errno == EAGAIN || errno == EWOULDBLOCK) {
					//并没有读取出错，只是底层没有连接了
					return 0;
				}
				if (errno == EINTR) {
					//读取过程被信号打断了
					continue;
				}
				else {
					//出错了
					return -1; 
				}
			}
			//成功读取完毕
			else {

				ns_until::SetNoBlock(sock);


				ns_epoll::EventItem tmp;
				tmp.sock = sock;
				tmp.R = item->R;
				tmp.ManagerCallBack(recver, sender, errorer);

				ns_epoll::Reactor* reactor = item->R;
			
 
				//epoll使用时，经常会设置读事件就绪，写事件就绪按需打开 
				reactor->AddEvent(sock, EPOLLIN | EPOLLET, tmp);
			}
		}
		return 0;
	}


	//return 0 success
	//return -1 error
	int recver_helper(int sock, std::string* out) {
		while (true) {
			char buffer[128];
			ssize_t size = recv(sock, buffer, sizeof(buffer) - 1, 0);
			if (size < 0) {
				if (errno == EAGAIN || errno == EWOULDBLOCK) {
					//循环读取，读取完毕了
					return  0;
				}
				else if (errno == EINTR) {
					//被信号中断，继续读
					continue;
				}
				else {
					//读取出错 ,//TODO
					return -1;
				}
			}
			else {
				buffer[size] = 0;
				*out += buffer; //将每次读取到的数据追加到inbuffer中
			}
		}
	}

	int recver(ns_epoll::EventItem* item) {
		std::cout << "recv event ready: " << item->sock << std::endl;
		//负责数据读取
		//1.需要整体读，非阻塞
		if (recver_helper(item->sock, &item->inbuffer) < 0) {
			//item->error_handler;
			return -1;
		}
		std::cout << "client#" << item->inbuffer << std::endl;
		
		//2.根据发来的数据流，进行包和包之间的分离，防止粘包
		std::vector<std::string> messages;
		ns_until::StringUtil::Split(item->inbuffer, &messages, "X");

		//3.针对一个一个的报文，协议反序列化decode
		//1+1X2*2X5%5X
		struct data {
			int x;
			int y;
		};

		//已经拿到了所有的数据报文
		for (auto s : messages) {
			struct data d;
			ns_until::StringUtil::Deserialize(s, &d.x, &d.y);
			std::cout << d.x << " : " << d.y << std::endl;

			//可以接入线程池
			//Task t(d)
			//threadpool->push

			//4.业务处理
			int z = d.x + d.y;

			//5.形成响应报文，序列化转化成为一个字符串
			std::string response;
			response += std::to_string(d.x);
			response += "+";
			response += std::to_string(d.y);
			response += "=";
			response += std::to_string(z);

			//响应报文追加进发送缓冲区
			item->outbuffer += response;
			//5.1 设置响应报文之间的分隔符
			item->outbuffer += "X"; //encode
		}
		//6.写回
		if(!item->outbuffer.empty())
			item->R->EnableReadWrite(item->sock, true, true);


		return 0;
	}

	//return 0 : 写完inbuffer
	//return 1 ：缓冲区打满，下次再写
	//return -1 : error
	int sender_helper(int sock, std::string& in) {

		size_t total = 0;

		while (true) {
			ssize_t s = send(sock, in.c_str() + total, in.size() - total, 0);

			if (s > 0) {
				total += s;
				if (total >= in.size()) {
					//已经写完
					return 0;
				}
			}
			else if(s < 0) {
				if (errno == EAGAIN || errno == EWOULDBLOCK) {
					//无论是否发送完inbuffer，都需要将已经发送的数据，全部移出缓冲区
					in.erase(total);

					return  1;//已经将缓冲区写满了，不能再写入了，但是不知道有没有写完
				}
				else if (errno == EINTR) {
					//被信号中断，继续写
					continue;
				}
				else {
					//写失败 ,//TODO
					return -1;
				}
			}
			else {
				//TODO
			}
		}
	}

	int sender(ns_epoll::EventItem* item) {
		int hret = sender_helper(item->sock, item->outbuffer);
		if (hret == 0) {
			//已经发完
			//关闭写
			item->R->EnableReadWrite(item->sock, true, false);
		}
		else if(hret == 1) {
			item->R->EnableReadWrite(item->sock, true, true);
		}
		else {
			//item->error_handler(item);
		}
		return 0;
	}
	int errorer(ns_epoll::EventItem* item) {
		/*close(item->sock);
		item->R->DelEvent(item->sock);*/
		return 0;
	}

}
